<script lang="ts" setup>
import type { FormInstance } from "element-plus";
import type { ColumnType, TableColumn } from "@/types/table";
import defaultStyle from "@/config/defaultConfig";
import {
  ElInput,
  ElInputNumber,
  ElSelect,
  ElCascader,
  ElCheckbox,
  ElRadio,
  ElDatePicker,
  ElTimePicker,
  // ElTimeSelect,
  ElSwitch,
  ElTreeSelect,
} from "element-plus";

import { useUrlDictStore, useEventSystem } from "@/store";
import { useI18n } from "vue-i18n";

const { t } = useI18n();
const TextConfig = computed(() => ({
  confirm: t("comps.common.confirm"),
  cancel: t("comps.common.cancel"),
  searchBtn: t("comps.table.search.searchBtn"),
  resetBtn: t("comps.table.search.resetBtn"),
  inputTip: t("comps.table.placeholder.input"),
  selectTip: t("comps.table.placeholder.select"),
}));

defineOptions({
  name: "BaseForm",
  inheritAttrs: false,
});

function useTextConfig() {
  const { rules = [], searchBtnText, cancelBtnText, emptyBtnText, saveBtnText } = useAttrs();
  return {
    searchBtnText: computed(() => searchBtnText ?? TextConfig.value.searchBtn),
    cancelBtnText: computed(() => cancelBtnText ?? TextConfig.value.cancel),
    emptyBtnText: computed(() => emptyBtnText ?? TextConfig.value.resetBtn),
    saveBtnText: computed(() => saveBtnText ?? TextConfig.value.confirm),
    rules,
  };
}

const { rules, searchBtnText, cancelBtnText, emptyBtnText, saveBtnText } = useTextConfig();

const ID: string = inject("channelID", "");
const { privatePublish } = useEventSystem();
const { dictData } = useUrlDictStore();
const formRef = ref<FormInstance>();
const props = withDefaults(
  defineProps<{
    columns?: TableColumn[] | null;
    isSearch?: boolean;
    labelWidth?: number | string;
    rowKey?: string;
  }>(),
  {
    columns: null,
    isSearch: false,
    labelWidth: defaultStyle.LabelWidth,
    rowKey: defaultStyle.RowKey,
  }
);
const emit = defineEmits<{
  search: [params: Record<string, unknown>];
  confirm: [params: Record<string, unknown>];
  cancel: [];
}>();

const elementDict: Partial<Record<ColumnType, Component>> = {
  input: ElInput,
  // textarea: ElInput,
  number: ElInputNumber,
  select: ElSelect,
  cascader: ElCascader,
  checkbox: ElCheckbox,
  radio: ElRadio,
  date: ElDatePicker,
  datetime: ElDatePicker,
  time: ElTimePicker,
  // timeSelect: ElTimeSelect,
  switch: ElSwitch,
  tree: ElTreeSelect,
};

const formState = reactive<Record<string, unknown>>({});

function getDefaultValue(type: string | undefined, multiple = false) {
  const defaults: Record<string, unknown> = {
    input: "",
    number: undefined,
    checkbox: false,
    switch: false,
    select: multiple ? [] : undefined,
    radio: undefined,
    date: null,
    datetime: null,
    time: null,
    cascader: [],
    upload: [],
    tree: multiple ? [] : undefined,
  };
  return defaults[type ?? "input"] ?? "";
}

// const multipleSet = new Set([]); // 记录需要把逗号分割字符串处理成

watch(
  () => props.columns,
  (newValue) => {
    if (newValue?.length) {
      newValue.forEach(({ prop, type, searchValue, multiple }) => {
        if (prop && !(prop in formState)) {
          let value = props.isSearch ? searchValue : undefined;
          formState[prop] = value ?? getDefaultValue(type, multiple);
        }
      });

      if (!props.isSearch) privatePublish(ID, "form:init", formState);
    }
  },
  { immediate: true }
);

onMounted(() => {
  // console.log("----form==========: ", props.isSearch, formState);
});

const onSearch = () => {
  emit("search", formState);
};
const onResetSearch = () => {
  if (!formRef.value) return;
  formRef.value?.resetFields();
};

const onCancel = () => {
  emit("cancel");
};
const onConfirm = () => {
  formRef.value?.validate((valid: boolean) => {
    if (valid) {
      privatePublish(ID, "form:submit", formState);
    }
  });
};
const renderComponent = (column: TableColumn) => {
  function getComponentType(typeName: string): ColumnType {
    return Object.keys(elementDict).includes(typeName) ? (typeName as ColumnType) : "input";
  }

  function generatePlaceholder(label: string | undefined, typeName: ColumnType) {
    if ("input" === typeName || "number" === typeName) return TextConfig.value.inputTip + label;
    if ("select" === typeName) return TextConfig.value.selectTip + label;
  }

  const {
    type: typeName = "input",
    label,
    prop,
    clearable = true,
    placeholder,
    dicData,
    dicUrl,
    props = { label: "label", value: "value", disabled: "disabled", options: "options" },
    ...columnProps
  } = column;

  const compKey = getComponentType(typeName);
  const comp = elementDict[compKey];
  const baseProps = {
    modelValue: formState[prop!],
    "onUpdate:modelValue": (value: unknown) => (formState[prop!] = value),
    placeholder: placeholder ?? generatePlaceholder(label, compKey),
    clearable,
    props,
    ...columnProps,
  };
  switch (compKey) {
    case "select": {
      let data = dicData ?? dictData.get(dicUrl!);
      return h(comp!, { baseProps, options: data });
    }
    case "tree": {
      // data 依赖于pinia的dictData，后面dicData变化是这个也会响应式更新
      let data = dicData ?? dictData.get(dicUrl!);
      return h(comp!, { ...baseProps, showCheckbox: true, data });
    }
    case "radio":
      return;
    case "checkbox":
      return;
    default:
      return h(comp!, baseProps);
  }
};
function fillField(data: Record<string, unknown>) {
  let rowKey = props.rowKey;
  formState[rowKey] = data[rowKey];
  props.columns?.forEach(({ prop, editFormatter }) => {
    // const { prop, formatter } = column;
    if (prop && prop in data) {
      let value = data[prop];
      formState[prop] = editFormatter ? editFormatter(value) : value;
    }
  });
}

defineExpose({ fillField });
</script>
<template>
  <el-form
    ref="formRef"
    :model="formState"
    :label-width="labelWidth"
    :rules="isSearch ? [] : rules!"
  >
    <el-row :gutter="20">
      <el-col
        v-for="(item, index) in columns"
        :key="index"
        :span="
          isSearch ? (item.searchSpan ?? defaultStyle.SearchSpan) : (item.span ?? defaultStyle.Span)
        "
      >
        <el-form-item :label="item.label" :prop="item.prop" :rules="isSearch ? [] : item.rules">
          <component :is="renderComponent(item)"></component>
        </el-form-item>
      </el-col>
      <el-col v-if="isSearch" :span="defaultStyle.SearchSpan">
        <el-form-item>
          <el-button type="primary" @click="onSearch">{{ searchBtnText }}</el-button>
          <el-button @click="onResetSearch">{{ emptyBtnText }}</el-button>
        </el-form-item>
      </el-col>
    </el-row>
    <el-row v-if="!isSearch" :span="24" justify="end">
      <el-form-item style="margin-bottom: 0">
        <el-button @click="onCancel">{{ cancelBtnText }}</el-button>
        <el-button type="primary" @click="onConfirm"> {{ saveBtnText }}</el-button>
      </el-form-item>
    </el-row>
  </el-form>
</template>
<style lang="scss" scoped></style>
